package com.oragraph.trials;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.geom.Point2D;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

import edu.uci.ics.jung.algorithms.layout.AbstractLayout;
import edu.uci.ics.jung.algorithms.layout.AggregateLayout;
import edu.uci.ics.jung.algorithms.layout.BalloonLayout;
import edu.uci.ics.jung.algorithms.layout.CircleLayout;
import edu.uci.ics.jung.algorithms.layout.DAGLayout;
import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.FRLayout2;
import edu.uci.ics.jung.algorithms.layout.ISOMLayout;
import edu.uci.ics.jung.algorithms.layout.KKLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.algorithms.layout.RadialTreeLayout;
import edu.uci.ics.jung.algorithms.layout.SpringLayout;
import edu.uci.ics.jung.algorithms.layout.SpringLayout2;
import edu.uci.ics.jung.algorithms.layout.StaticLayout;
import edu.uci.ics.jung.algorithms.layout.TreeLayout;
import edu.uci.ics.jung.algorithms.layout.util.Relaxer;
import edu.uci.ics.jung.algorithms.layout.util.VisRunner;
import edu.uci.ics.jung.algorithms.util.IterativeContext;
import edu.uci.ics.jung.graph.DelegateForest;
import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
import edu.uci.ics.jung.graph.Forest;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.util.TreeUtils;
import edu.uci.ics.jung.visualization.BasicVisualizationServer;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.layout.CachingLayout;
import edu.uci.ics.jung.visualization.layout.LayoutTransition;
import edu.uci.ics.jung.visualization.subLayout.TreeCollapser;
import edu.uci.ics.jung.visualization.util.Animator;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse; 


public class Trial1 extends JPanel {
	
	private JTextField toAddField;
	public static Trial1 singleton;	
	private DefaultModalGraphMouse graphMouse;
	private VisualizationViewer<Trial1Node,Trial1Edge> visualizationServer;
	
	private Layout<Trial1Node, Trial1Edge> layout;
	//private AbstractLayout<Trial1Node, Trial1Edge> layout;
	
	//private Graph<Trial1Node,Trial1Edge> graph;
	private Forest<Trial1Node,Trial1Edge> graph;
	
	private Trial1Node rootNode;
	
	public static void main(String args[]) {
		try {
			JFrame frame = new JFrame("OraGraph Trial 1");
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			Container content = frame.getContentPane();
			content.add(new Trial1());
			frame.pack();
			frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
			frame.setVisible(true);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public Trial1() {
		singleton=this;
		
		_initGraph();
		
		// CREATE GRAPH VISUALIZATION ---------------------------------------------
		
		layout=_createLayout();
		
		
//		layout=new CachingLayout(layout);
		
//		layout.setSize(new Dimension(5000,5000));		
//		layout.setLocation(rootNode, new Point(100,100));
		
//		Relaxer relaxer = new VisRunner((IterativeContext)layout);
//		relaxer.stop();
//		relaxer.prerelax();

//		Layout<Trial1Node,Trial1Edge> staticLayout=
//			new StaticLayout<Trial1Node,Trial1Edge>(graph, layout);
		
//		visualizationServer=new VisualizationViewer<Trial1Node,Trial1Edge>(staticLayout);
		visualizationServer=new VisualizationViewer<Trial1Node,Trial1Edge>(layout);
//		visualizationServer.setPreferredSize(new Dimension(600,600));
		
//		visualizationServer.getRenderContext().getMultiLayerTransformer().setToIdentity();
		
		visualizationServer.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
		
		graphMouse = new DefaultModalGraphMouse();
		graphMouse.setMode(ModalGraphMouse.Mode.PICKING);
		visualizationServer.setGraphMouse(graphMouse);
		
		visualizationServer.addKeyListener(graphMouse.getModeKeyListener());
		
        visualizationServer.addComponentListener(new ComponentAdapter() {
			public void componentResized(ComponentEvent arg0) {
				super.componentResized(arg0);
				layout.setSize(arg0.getComponent().getSize());
			}});
		
        GraphZoomScrollPane graphPanel = new GraphZoomScrollPane(visualizationServer);
		
		// CREATE SWING AROUND ----------------------------------------------------
		
		// ADD CHILDREN
		JLabel toAddLabel=new JLabel("Number of children to add:");
		toAddField=new JTextField(10);
		JButton toAddButton=new JButton("Add");
		toAddButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Trial1.singleton.addChildren();
            }
        });		
		
		JPanel addChildrenPanel=new JPanel();
		addChildrenPanel.add(toAddLabel);
		addChildrenPanel.add(toAddField);
		addChildrenPanel.add(toAddButton);
		
		addChildrenPanel.setBorder(BorderFactory.createTitledBorder("Add children"));
		
		// EXPAND-COLLAPSE
		JButton collapseButton=new JButton("Collapse");
		collapseButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Trial1.singleton.collapse();
            }
        });	
		
		JButton expandButton=new JButton("Expand");
		expandButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                Trial1.singleton.expand();
            }
        });	
		
		JPanel expandCollapsePanel=new JPanel();
		expandCollapsePanel.add(collapseButton);
		expandCollapsePanel.add(expandButton);
		
		expandCollapsePanel.setBorder(BorderFactory.createTitledBorder("Manipulation"));
		
		// MAIN PANEL
		
		JPanel bottomPanel=new JPanel();
		bottomPanel.add(addChildrenPanel);
		bottomPanel.add(expandCollapsePanel);
		
		this.setLayout(new BorderLayout());
		this.add(bottomPanel, BorderLayout.SOUTH);
		//this.add(visualizationServer, BorderLayout.CENTER);
		this.add(graphPanel, BorderLayout.CENTER);
		
	}
	
	public void addChildren() {
		Collection picked = new HashSet(visualizationServer.getPickedVertexState().getPicked());
		if(picked.size()==1) {
			Object[] selected=picked.toArray();
			if (selected[0] instanceof Trial1Node) {
				Trial1Node selectedNode=(Trial1Node)selected[0];
				int numToAdd=Integer.parseInt(toAddField.getText());
//				layout.lock(true);
//                Relaxer relaxer = visualizationServer.getModel().getRelaxer();
//                relaxer.pause();

//				Vector<Trial1Node> newlyAddedNodes=new Vector<Trial1Node>();
				
				for (int i=0; i<numToAdd; i++) {
					Trial1Node nodeToAdd=new Trial1Node(selectedNode.name+"_"+i);
					selectedNode.children.add(nodeToAdd);
					graph.addVertex(nodeToAdd);
					Trial1Edge edgeToAdd=new Trial1Edge();
					graph.addEdge(edgeToAdd, selectedNode, nodeToAdd);
//					newlyAddedNodes.add(nodeToAdd);
				}			
				
				Layout<Trial1Node, Trial1Edge> newLayout=_createLayout();
//				visualizationServer.setGraphLayout(newLayout);
				
				//layout.initialize();
				
//				layout.lock(false);
				
//        		Relaxer relaxer = new VisRunner((IterativeContext)layout);
//        		relaxer.stop();
//        		relaxer.prerelax();
//        		
				LayoutTransition<Trial1Node,Trial1Edge> lt = 
					new LayoutTransition<Trial1Node,Trial1Edge>(visualizationServer, 
							visualizationServer.getGraphLayout(), newLayout);
				
				Animator animator = new Animator(lt);
				animator.start();

				visualizationServer.repaint();				
			}
		}
	}
	
	public void expand() {
		Collection picked = new HashSet(visualizationServer.getPickedVertexState().getPicked());
		if(picked.size()==1) {
			Object[] selected=picked.toArray();
			if (selected[0] instanceof Forest) {
				Forest selectedForest=(Forest)selected[0];
				TreeCollapser collapser=new TreeCollapser();

                try {
					collapser.expand(graph, selectedForest);
				} 
                catch (Exception e) {
					e.printStackTrace();
				}

                visualizationServer.getPickedVertexState().clear();
                visualizationServer.repaint();				
			}
		}
		
	}
	
	public void collapse() {
		Collection picked = new HashSet(visualizationServer.getPickedVertexState().getPicked());
		if(picked.size()==1) {
			Object[] selected=picked.toArray();
			if (selected[0] instanceof Trial1Node) {
				Trial1Node selectedNode=(Trial1Node)selected[0];
				TreeCollapser collapser=new TreeCollapser();

                try {
					collapser.collapse(visualizationServer.getGraphLayout(), 
							graph, selectedNode);
				} 
                catch (Exception e) {
					e.printStackTrace();
				}

                visualizationServer.getPickedVertexState().clear();
                visualizationServer.repaint();				
			}
		}
	}
	
	private void _initGraph() {
		//graph=new DirectedSparseMultigraph<Trial1Node,Trial1Edge>();
		graph=new DelegateForest<Trial1Node,Trial1Edge>();
		
		rootNode=new Trial1Node("root");
		graph.addVertex(rootNode);
		
		for (int i=0; i<5; i++) {
			Trial1Node nodeToAdd=new Trial1Node(rootNode.name+"_"+i);
			rootNode.children.add(nodeToAdd);
			graph.addVertex(nodeToAdd);
			Trial1Edge edgeToAdd=new Trial1Edge();
			graph.addEdge(edgeToAdd, rootNode, nodeToAdd);
			
			for (int j=0; j<5; j++) {
				Trial1Node nodeToAdd2=new Trial1Node(nodeToAdd.name+"_"+i);
				nodeToAdd.children.add(nodeToAdd2);
				graph.addVertex(nodeToAdd2);
				Trial1Edge edgeToAdd2=new Trial1Edge();
				graph.addEdge(edgeToAdd2, nodeToAdd, nodeToAdd2);				
			}
		}			

	}

	private Layout<Trial1Node, Trial1Edge> _createLayout() {
//		return new FRLayout(graph);
//		return new FRLayout2(graph);
//		return new CircleLayout(graph);
//		return new KKLayout(graph);
//		return new ISOMLayout(graph);
//		return new DAGLayout(graph);
//		return new SpringLayout(graph);
//		return new SpringLayout2(graph);
//		return new RadialTreeLayout<Trial1Node,Trial1Edge>(graph);
		return new BalloonLayout<Trial1Node,Trial1Edge>(graph);
//		return new TreeLayout<Trial1Node,Trial1Edge>(graph);
	}
	
}
